/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkStateGridBUt.h"
#include "MkStateGridB/MkStateGridB.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"
#include "MkSdp/MkSdp.h"
#include "MkUtil/MkMemQueue.h"

CMkStateGridBUt::CMkStateGridBUt()
{

}

CMkStateGridBUt::~CMkStateGridBUt()
{

}

void CMkStateGridBUt::SetUp()
{
    m_pServer = nullptr;
    m_pDevice = nullptr;
    m_WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    m_pEventPool = new CMkEventPool;
    m_pEventPool->Start(1);
    m_pTimer = new CMkTimer;
    m_pTimer->StartTimerThread();

    m_ServerId = "191000000000000001";
    m_DeviceId = "191000000000000002";
    m_Realm = "1910000000";

    MkStateGridBStartParam ServerParam;
    ServerParam.LocalHost = "127.0.0.1";
    ServerParam.MappingHost = "";
    ServerParam.MappingPort = 0;
    ServerParam.RegisterExpires = 1;
    ServerParam.SipId = m_ServerId;
    ServerParam.SipRealm = m_Realm;
    ServerParam.SubscribeExpires = 1;
    m_pServer = new CMkStateGridB(m_pEventPool, m_pTimer);
    while (1) {
        m_ServerPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        ServerParam.LocalPort = m_ServerPort;
        if (NoneError == m_pServer->Start(ServerParam, [this](const CMkStateGridBRequestBase* pRequest, const MkStateGridBResponseCallback& ResCb) {
            return OnServerRequest(pRequest, ResCb);
        })) {
            break;
        }
    }

    MkStateGridBStartParam DeviceParam;
    DeviceParam.LocalHost = "127.0.0.1";
    DeviceParam.MappingHost = "";
    DeviceParam.MappingPort = 0;
    DeviceParam.RegisterExpires = 1;
    DeviceParam.SipId = m_DeviceId;
    DeviceParam.SipRealm = m_Realm;
    DeviceParam.SubscribeExpires = 1;
    m_pDevice = new CMkStateGridB(m_pEventPool, m_pTimer);
    while (1) {
        m_DevicePort = CMkUtil::GetRandomNumber() % 0xFFFF;
        DeviceParam.LocalPort = m_DevicePort;
        if (NoneError == m_pDevice->Start(DeviceParam, [this](const CMkStateGridBRequestBase* pRequest, const MkStateGridBResponseCallback& ResCb) {
            return OnDeviceRequest(pRequest, ResCb);
        })) {
            break;
        }
    }
    m_pDevice->AddRouter(m_ServerId, m_Realm, "127.0.0.1", m_ServerPort, FALSE);
    RegisterServer(m_pDevice, m_ServerId, 1, MkMapString(), [this]() {
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}


Uint32 CMkStateGridBUt::RegisterServer(CMkStateGridB* pSvr, const MkString& ServerId, Uint32 Expires, const MkMapString& AuthorizationParam, const RegCallback& Cb)
{
    if (AuthorizationParam.empty()) {
        return pSvr->RegisterServer(ServerId, Expires, [pSvr, ServerId, Expires, this, Cb](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
            const CMkStateGridBRegisterResponse* pRes = dynamic_cast<const CMkStateGridBRegisterResponse*>(pResponse);
            if (pRes
                &&NoneError == ErrorCode) {
                if (MkSipStatusUnauthorized == pRes->GetStatusCode()) {
                    MkMapString MapParam;
                    MapParam["username"] = "\"123\"";
                    MapParam["realm"] = "\"" + pRes->GetUpRealm() + "\"";
                    MapParam["nonce"] = "\"" + pRes->GetUpNonce();
                    MapParam["uri"] = "\"sip:xxx@1122\"";
                    MapParam["response"] = "\"123\"";
                    MapParam["algorithm"] = pRes->GetUpAlgorithm();
                    m_RegisterId = pRes->GetRegisterId();
                    RegisterServer(pSvr, ServerId, Expires, MapParam, Cb);
                } else if (MkSipStatusOK == pRes->GetStatusCode()) {
                    MkDebugLog("register server success\n");
                    Cb();
                } else {
                    ErrorCode = InvalidParams;
                }
            }
        });
    } else {
        return pSvr->RegisterServerWithRegisterId(m_RegisterId, Expires, AuthorizationParam, [Cb](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse)
        {
            if (NoneError == ErrorCode) {
                Cb();
            }
            MkDebugLog("register server error:%d\n", ErrorCode);
        });
    }
}

Uint32 CMkStateGridBUt::OnServerRequest(const CMkStateGridBRequestBase* pRequest, const MkStateGridBResponseCallback& ResCb)
{
    switch (pRequest->GetMsgType()) {
    case MkStateGridBRegister:
    {
        ResCb(NoneError, nullptr);
        const CMkStateGridBRegisterRequest* pRegReq = dynamic_cast<const CMkStateGridBRegisterRequest*>(pRequest);
        if (pRegReq && 0 != pRegReq->GetExpires()) {
            m_pDevice->GetEventPool()->GetFreeEvent()->AddPipTask([this]() {
                MkStateGridBResourseItem Item;
                Item.Code = "191000000001110002";
                Item.Status = TRUE;
                Item.Name = "TestResource";
                Item.DecodeTag = 100;
                Item.Latitude = 0.1f;
                Item.Longitude = 0.1f;
                Item.SubNum = 1;
                MkMapStateGridBResourse MapResouce;
                MapResouce[Item.Code] = Item;
                m_pDevice->ResourcePush(m_ServerId, m_ServerId, m_DeviceId, MapResouce, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
                    EXPECT_EQ(NoneError, ErrorCode);
                });
            });
        }
        return NoneError;
    }
    break;
    default:
        break;
    }
    ResCb(NoneError, nullptr);
    return NoneError;
}

Uint32 CMkStateGridBUt::OnDeviceRequest(const CMkStateGridBRequestBase* pRequest, const MkStateGridBResponseCallback& ResCb)
{
    switch (pRequest->GetMsgType()) {
    case MkStateGridBResoursePush:
        break;
    case MkStateGridBGetResourse:
    {
        MkStateGridBResourseItem Item;
        Item.Code = "191000000001110002";
        Item.Status = TRUE;
        Item.Name = "TestResource";
        Item.DecodeTag = 100;
        Item.Latitude = 0.1f;
        Item.Longitude = 0.1f;
        Item.SubNum = 1;
        MkMapStateGridBResourse MapResouce;
        MapResouce[Item.Code] = Item;
        CMkStateGridBGetResourceResponse GetResourceRes(pRequest->GetRouterId(), pRequest->GetDstId(), "191000000000000002", 1, 1, 0, 1, MapResouce);
        ResCb(NoneError, &GetResourceRes);
        return NoneError;
    }
    break;
    case MkStateGridBGetAlarm:
    {
        MkStateGridBAlarmItem Item;
        Item.AlarmType = 1;
        Item.Status = 1;
        Item.Code = "191000000001320002";
        Item.BeginTime = NowMkTime;
        MkVectorStateGridBAlarm VecAlarm;
        VecAlarm.emplace_back(Item);
        CMkStateGridBGetAlarmResponse AlarmRes(pRequest->GetRouterId(), pRequest->GetDstId(), 1, 1, 0, 1, VecAlarm);
        ResCb(NoneError, &AlarmRes);
        return NoneError;
    }
    break;
    case MkStateGridBGetRecord:
    {
        MkStateGridBRecordItem Item;
        Item.FileName = "fileName";
        Item.RtspUrl = "rtsp://128.0.0.1/aaa/aa";
        Item.BeginTime = NowMkTime;
        Item.EndTime = NowMkTime;
        Item.FileSize = 1;
        Item.DecoderTag = 100;
        Item.RecordType = 1;
        MkVectorStateGridBRecord VecRecord;
        VecRecord.emplace_back(Item);
        CMkStateGridBGetRecordResponse Res(pRequest->GetRouterId(), pRequest->GetDstId(), 1, 1, 0, 1, VecRecord);
        ResCb(NoneError, &Res);
        return NoneError;
    }
    break;
    case MkStateGridBMedia:
    {
        CMkSdp Sdp;
        CMkSdpMedia SdpMedia;
        Sdp.SetOrigin(CMkOrigin(m_ServerId, "0", "0", "IN", "IP4", "127.0.0.1"));
        Sdp.SetConnection(CMkSdpConnection("IN", "IP4", "127.0.0.1"));
        SdpMedia.SetPort(848);
        SdpMedia.SetProtocol("RTP/AVP");

        Sdp.SetVersion("0");
        Sdp.SetSessionName("Play");
        SdpMedia.SetMediaType("video");
        CMkSdpFmt SdpFmt;
        SdpFmt.SetPayload(100);
        SdpFmt.SetEncodingName("PS");
        SdpFmt.SetClockRate(90000);
        SdpMedia.AddFmt(SdpFmt);
        SdpMedia.AddAttr(CMkSdpAttribute("sendonly"));
        Sdp.AddMedia(SdpMedia);
        MkString AnswerSdp;
        Sdp.ToString(AnswerSdp);
        CMkStateGridBMediaResponse MediaRes(pRequest->GetRouterId(), pRequest->GetDstId(), "123", AnswerSdp, nullptr);
        ResCb(NoneError, &MediaRes);
        return NoneError;
    }
    break;
    case MkStateGridBSubscribe:
    {
        const CMkStateGridBSubscribeRequest *pSubReq = dynamic_cast<const CMkStateGridBSubscribeRequest*>(pRequest);
        if (pSubReq) {
            CMkStateGridBSubscribeResponse Res(pRequest->GetRouterId(), pRequest->GetDstId(), pSubReq->GetSubscribeId(), 3600);
            ResCb(NoneError, &Res);

            if (MkStateGridBSubscribeAlarm == pSubReq->GetSubscribeType()) {
                m_pDevice->AlarmNotify(pSubReq->GetSubscribeId(), "active", "191000000001320002", "testAlarm", 1, NowMkTime, NowMkTime, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
                    EXPECT_EQ(NoneError, ErrorCode);
                });
            } else {
                m_pDevice->StateNotify(pSubReq->GetSubscribeId(), "active", "191000000001310002", "testState", 1, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
                    EXPECT_EQ(NoneError, ErrorCode);
                });
            }
            return NoneError;
        }
    }
    break;
    case MkStateGridBMediaShutDown:
        break;
    case MkStateGridBPtzControl:
        break;
    default:
        break;
    }
    ResCb(NoneError, nullptr);
    return NoneError;
}

void CMkStateGridBUt::TearDown()
{
    RegisterServer(m_pDevice, m_ServerId, 0, MkMapString(), [this]() {
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
    CMkThread::ThreadSleep(100);
    m_pTimer->StopTimerThread();
    m_pEventPool->Stop();
    m_pServer->Stop();
    m_pDevice->Stop();
    CloseHandle(m_WaitHandle);
    MkDelete(m_pServer);
    MkDelete(m_pDevice);
    MkDelete(m_pTimer);
    MkDelete(m_pEventPool);
}

TEST_F(CMkStateGridBUt, RealPlayTest)
{
    CMkSdp Sdp;
    CMkSdpMedia SdpMedia;
    Sdp.SetOrigin(CMkOrigin(m_ServerId, "0", "0", "IN", "IP4", "127.0.0.1"));
    Sdp.SetConnection(CMkSdpConnection("IN", "IP4", "127.0.0.1"));
    SdpMedia.SetPort(424);
    SdpMedia.SetProtocol("RTP/AVP");

    Sdp.SetVersion("0");
    Sdp.SetSessionName("Play");
    SdpMedia.SetMediaType("video");
    CMkSdpFmt SdpFmt;
    SdpFmt.SetPayload(100);
    SdpFmt.SetEncodingName("PS");
    SdpFmt.SetClockRate(90000);
    SdpMedia.AddFmt(SdpFmt);
    SdpMedia.AddAttr(CMkSdpAttribute("recvonly"));
    Sdp.AddMedia(SdpMedia);
    MkString OfferSdp;
    Sdp.ToString(OfferSdp);
    Uint32 ErrorCode = m_pServer->InviteStream("191000000000000002", "191000000000000002", OfferSdp, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        const CMkStateGridBMediaResponse* pMediaRes = dynamic_cast<const CMkStateGridBMediaResponse*>(pResponse);
        EXPECT_NE(nullptr, pMediaRes);
        if (pMediaRes) {
            m_PlaySession = pMediaRes->GetSessionId();
            if (pMediaRes->GetEventCb()) {
                pMediaRes->GetEventCb()(MkMapString(), "");
            }
        }
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);

    ErrorCode = m_pServer->ByeStream(m_PlaySession, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkStateGridBUt, MessageTest)
{
    Uint32 ErrorCode = m_pServer->PtzControl("191000000000000002", "191000000000000002", MkStateGridPtzZoomIn, 1, 1, 1, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);

    ErrorCode = m_pServer->GetResourse("191000000000000002", "191000000000000002", 0, 100, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);

    ErrorCode = m_pServer->GetHistoryAlarm("191000000000000002", "191000000000000002", 0, NowMkTime, NowMkTime, 1, 0, 100, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);

    ErrorCode = m_pServer->FindRecord("191000000000000002", "191000000000000002", MkStateGridBRecordAll, NowMkTime, NowMkTime, 0, 100, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkStateGridBUt, AlarmSubscribeTest)
{
    MkMap<MkString, Uint32> MapSubId;
    MapSubId["191000000000000002"] = 1;
    Uint32 ErrorCode = m_pServer->EventSubscribe("191000000000000002", "191000000000000002", 1, MkStateGridBSubscribeAlarm, MapSubId, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        const CMkStateGridBSubscribeResponse* pSubRes = dynamic_cast<const CMkStateGridBSubscribeResponse*>(pResponse);
        EXPECT_NE(nullptr, pSubRes);
        if (pSubRes) {
            m_AlaramSubscribeId = pSubRes->GetSubscribeId();
        }
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
    CMkThread::ThreadSleep(100);  //wait notify
    m_pServer->StopEventSubscirbe(m_AlaramSubscribeId, MkStateGridBSubscribeAlarm, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkStateGridBUt, StateSubscribeTest)
{
    MkMap<MkString, Uint32> MapSubId;
    MapSubId["191000000000000002"] = 0;
    Uint32 ErrorCode = m_pServer->EventSubscribe("191000000000000002", "191000000000000002", 1, MkStateGridBSubscribeStatus, MapSubId, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        const CMkStateGridBSubscribeResponse* pSubRes = dynamic_cast<const CMkStateGridBSubscribeResponse*>(pResponse);
        EXPECT_NE(nullptr, pSubRes);
        if (pSubRes) {
            m_StatusSubscribeId = pSubRes->GetSubscribeId();
        }
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
    CMkThread::ThreadSleep(100);  //wait notify
    m_pServer->StopEventSubscirbe(m_StatusSubscribeId, MkStateGridBSubscribeStatus, [this](Uint32 ErrorCode, const CMkStateGridBResponseBase* pResponse) {
        EXPECT_EQ(NoneError, ErrorCode);
        SetEvent(m_WaitHandle);
    });
    EXPECT_EQ(ErrorCode, NoneError);
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}